package com.langyiquan.service.impl;

import com.langyiquan.enums.CommentLevel;
import com.langyiquan.enums.YesOrNo;
import com.langyiquan.exception.http.NotFoundException;
import com.langyiquan.mapper.*;
import com.langyiquan.mapper.custom.ItemCustomMapper;
import com.langyiquan.pojo.*;
import com.langyiquan.service.ItemService;
import com.langyiquan.utils.DesensitizationUtil;
import com.langyiquan.utils.PagedGridResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.langyiquan.vo.CommentLevelCountVO;
import com.langyiquan.vo.ItemCommentVO;
import com.langyiquan.vo.CommonItemsVO;
import com.langyiquan.vo.ShopcartVO;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import java.util.*;
import com.langyiquan.vo.ItemBaseInfoVO;

@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private ItemsMapper itemsMapper;

    @Autowired
    private ItemImgMapper itemImgMapper;

    @Autowired
    private ItemSpecMapper itemSpecMapper;

    @Autowired
    private ItemCommentMapper itemCommentMapper;

    @Autowired
    private ItemCustomMapper itemCustomMapper;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public ItemBaseInfoVO queryItemById(String id) {
        Map<String,Object> map= new HashMap<String,Object>();
        map.put("itemId",id);
        ItemBaseInfoVO itemBaseInfoVO = itemCustomMapper.queryItemInfo(map);
        return itemBaseInfoVO;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ItemImg> queryItemImgsList(String itemId) {
        Example example = new Example(ItemImg.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("itemId", itemId);
        List<ItemImg> result = itemImgMapper.selectByExample(example);
        return result;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ItemSpec> queryItemSpecsList(String itemId) {
        Example example = new Example(ItemSpec.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("itemId", itemId);
        List<ItemSpec> result = itemSpecMapper.selectByExample(example);
        return result;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public CommentLevelCountVO queryCommentCounts(String itemId) {

        Integer goodCounts = _getCommentCounts(itemId, CommentLevel.GOOD.type);
        Integer normalCounts = _getCommentCounts(itemId,CommentLevel.NORMAL.type);
        Integer badCounts = _getCommentCounts(itemId,CommentLevel.BAD.type);
        Integer totalCounts = goodCounts+normalCounts+badCounts;
        CommentLevelCountVO commentLevelCountVO = new CommentLevelCountVO();
        commentLevelCountVO.setTocalCounts(totalCounts);
        commentLevelCountVO.setGoodCounts(goodCounts);
        commentLevelCountVO.setNormalCounts(normalCounts);
        commentLevelCountVO.setBadCounts(badCounts);
        return commentLevelCountVO;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public PagedGridResult queryPagedComments(String itemId, Integer level,Integer page,Integer pageSize) {
        Map<String,Object> map= new HashMap<String,Object>();
        map.put("itemId",itemId);
        map.put("level",level);

        PageHelper.startPage(page,pageSize);
        List<ItemCommentVO> list = itemCustomMapper.queryItemComments(map);

        for (ItemCommentVO vo :list){
            vo.setNickname(DesensitizationUtil.commonDisplay(vo.getNickname()));
        }

        PageInfo<?> pageList = new PageInfo<>(list);
        PagedGridResult grid = new PagedGridResult();
        grid.setPage(page);
        grid.setRows(list);
        grid.setTotal(pageList.getPages());
        grid.setRecords(pageList.getTotal());

        return grid;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public PagedGridResult searchItems(String keywords, String sort, Integer page, Integer pageSize) {

        Map<String,Object> map= new HashMap<String,Object>();
        map.put("keywords",keywords);
        map.put("sort",sort);

        PageHelper.startPage(page,pageSize);
        List<CommonItemsVO> list = itemCustomMapper.searchItems(map);
        PageInfo<?> pageList = new PageInfo<>(list);
        PagedGridResult grid = new PagedGridResult();
        grid.setPage(page);
        grid.setRows(list);
        grid.setTotal(pageList.getPages());
        grid.setRecords(pageList.getTotal());

        return grid;

    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public PagedGridResult esSearchItems(String keywords, String sort, Integer page, Integer pageSize) {

        String preTag = "<font color='red'>";
        String postTag = "</font>";
        String searchName = "itemName";
        Pageable pageable = PageRequest.of(page,pageSize);
        SortBuilder sortBuilder = null;
        if(sort.equals("c")){
            sortBuilder = new FieldSortBuilder("sellCounts").order(SortOrder.DESC);
        }else if(sort.equals("p")){
            sortBuilder = new FieldSortBuilder("price").order(SortOrder.ASC);
        }else{
            sortBuilder = new FieldSortBuilder("itemName.keyword").order(SortOrder.ASC);
        }

        SearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery(searchName,keywords))
                .withHighlightFields(new HighlightBuilder.Field(searchName).preTags(preTag).postTags(postTag))
                .withPageable(pageable)
                .withSort(sortBuilder)
                .build();

        AggregatedPage<SearchItems> searchItems = elasticsearchTemplate.queryForPage(query, SearchItems.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                List<SearchItems> list = new ArrayList<>();
                SearchHits hits = searchResponse.getHits();
                for (SearchHit h: hits){
                    HighlightField highlightField = h.getHighlightFields().get("itemName");
                    SearchItems items = new SearchItems();
                    items.setItemId((String)h.getSourceAsMap().get("itemId"));
                    items.setItemName(highlightField.getFragments()[0].toString());
                    items.setImgUrl((String)h.getSourceAsMap().get("imgUrl"));
                    items.setPrice((Integer)h.getSourceAsMap().get("price"));
                    items.setSellCounts((Integer)h.getSourceAsMap().get("sellCounts"));
                    list.add(items);
                }

                return new AggregatedPageImpl<>((List<T>)list,pageable,searchResponse.getHits().totalHits);

            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                return null;
            }

        });

        PagedGridResult grid = new PagedGridResult();
        grid.setRows(searchItems.getContent());
        grid.setPage(page+1);
        grid.setTotal(searchItems.getTotalPages());
        grid.setRecords(searchItems.getTotalElements());
        return grid;

    }

    @Override
    public PagedGridResult getRecommendItems(Integer page, Integer pageSize) {

        PageHelper.startPage(page,pageSize);
        List<CommonItemsVO> list = itemCustomMapper.getRecommendItems();

        PageInfo<?> pageList = new PageInfo<>(list);
        PagedGridResult grid = new PagedGridResult();
        grid.setPage(page);
        grid.setRows(list);
        grid.setTotal(pageList.getPages());
        grid.setRecords(pageList.getTotal());

        return grid;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ShopcartVO> queryItemsBySpecIds(String specIds) {
        String ids[] = specIds.split(",");
        List<String> specList= new ArrayList<>();
        Collections.addAll(specList,ids);
        return itemCustomMapper.queryItemsBySpecIds(specList);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public ItemSpec queryItemSpecById(String specId) {
        return itemSpecMapper.selectByPrimaryKey(specId);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public String queryItemMainImgById(String itemId) {
        ItemImg itemsImg = new ItemImg();
        itemsImg.setItemId(itemId);
        itemsImg.setIsMain(YesOrNo.YES.type);
        ItemImg result = itemImgMapper.selectOne(itemsImg);
        return result != null ? result.getUrl() : "";
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public void decreaseItemSpecStock(String itemSpecId, Integer buyCount) {
        int result = itemCustomMapper.decreaseItemSpecStock(itemSpecId,buyCount);
        if(result != 1){
            throw new NotFoundException(6010);
        }
    }

    private Integer _getCommentCounts(String itemId,Integer level){

        ItemComment condition = new ItemComment();
        condition.setItemId(itemId);
        if(level != null){
            condition.setCommentLevel(level);
        }
        return itemCommentMapper.selectCount(condition);

    }

}
